﻿using System;
using System.Linq;
using AltSerialize;
using System.Net.Sockets;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using BrainTechLLC.Silverlight.HigherLevelControls.DataService;
using BrainTechLLC;
using BrainTechLLC.ThreadSafeObjects;
using BrainTechLLC.Communication;
using System.Threading;
using System.Runtime.Serialization;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Reflection;
using System.Diagnostics;

namespace BrainTechLLC.Silverlight.ClientApplication
{
    public static class DataAccess
    {
        public static object _lock = new object();
        public static int AssignedUniqueId = 0;
        public static event EventHandler LoginSuccessful;
        public static event EventHandler LoginUnsuccessful;
        public static event EventHandler UsersGameCharactersRead;
        public static event EventHandler EnteredGame;
        public static event EventHandler GameCharactersRead;
        public static event EventHandler CurrentlyPlayingChanged;
        public static event EventHandler WantEnableHUD;
        public static event EventHandler LocalWorldRead;
        public static event EventHandler<ObjectEventArgs<ByteDataMessage>> RequestAllLocationsComplete;
        public static event EventHandler<ObjectEventArgs<ByteDataMessage>> RequestAllGameCharTemplatesComplete;
        public static event EventHandler<ObjectEventArgs<ByteDataMessage>> RequestAllItemTemplatesComplete;
        public static event EventHandler<ObjectEventArgs<ByteDataMessage>> RequestAllItemsComplete;
        public static event EventHandler<ObjectEventArgs<ByteDataMessage>> RequestAllAreasComplete;
        public static event EventHandler<ObjectEventArgs<ByteDataMessage>> RequestAllLocationEdgesComplete;
        public static event EventHandler<ObjectEventArgs<ByteDataMessage>> RequestAllGameCharsComplete;
        public static event EventHandler<ObjectEventArgs<ByteDataMessage>> RequestAllResetsComplete;
        public static event EventHandler<ObjectEventArgs<ByteDataMessage>> RequestObjectByIdComplete;
        public static event EventHandler<ObjectEventArgs<Type, ByteDataMessage>> RequestComplete;

        public static event EventHandler<ObjectEventArgs<string>> NotificationTextReceived;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreAbilityCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreGameCharCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreGameLocationCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreGameCharTemplateCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreItemTemplateCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreItemCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreGameThingCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreStateCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreMediaCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreStateTemplateCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreTemplateCompleted;
        public static event EventHandler<ObjectEventArgs<string, object>> UpdatePropertyValue;
        public static event EventHandler<ObjectEventArgs<SocketAsyncEventArgs>> SocketErrorOccurred;
        public static event EventHandler<ObjectEventArgs<SocketAsyncEventArgs>> ConnectionErrorOccurred;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreChannelCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreAreaCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreResetCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreEdgeDataCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> StoreLocationEdgeCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long, LocationInt, long>> ThingMoved;

        public static event EventHandler<ObjectEventArgsNonRef<long>> CreateItemCompleted;
        public static event EventHandler<ObjectEventArgsNonRef<long>> CreateCharCompleted;

        public static ObservableCollection<Channel> Channels;
        public static bool Initialized = false;
        public static long LastStoredId;
        public static UsernamePassword CurrentLogin;
        public static readonly string RemoteHostName = "";
        public static DataServiceClient Client;
        private static SilverlightCommClient _communications;
        public static List<GameChar> UsersGameCharacters = new List<GameChar>();
        public static List<GameChar> GameCharacters = new List<GameChar>();
        public static SparseArrayCustom<GameLocation> LocalWorld = new SparseArrayCustom<GameLocation>();
        public static GameChar CurrentlyPlaying = null;
        public static ObservableCollection<IdentifierAndValue> PropertiesInstance;
        public static long CurrentlyPlayingId = 0;
        public static List<Method> _methods;

        public static void ChangePropertyValueLocally(string propName, object newValue)
        {
            var propertyFound = PropertiesInstance.FirstOrDefault((p) => p._identifier.Equals(propName, StringComparison.OrdinalIgnoreCase));
            if (propertyFound != null)
            {
                propertyFound.Value = newValue;
            }
        }

        public static string DownloadSingleObject(long id)
        {
            // HEREHERE Communications.SendMessage(new RequestObjectById() { ID = id });
            return string.Empty;
        }

        public static string DownloadData(params Type[] types)
        {
            foreach (Type t in types)
            {
                if (t == typeof(ItemTemplate))
                    Communications.SendMessage(new RequestAllItemTemplates());
                else if (t == typeof(GameCharTemplate))
                    Communications.SendMessage(new RequestAllGameCharTemplates());
                else if (t == typeof(GameChar))
                    Communications.SendMessage(new RequestAllGameChars());
                else if (t == typeof(Item))
                    Communications.SendMessage(new RequestAllItems());
                else if (t == typeof(Area))
                    Communications.SendMessage(new RequestAllAreas());
                else if (t == typeof(LocationEdge))
                    Communications.SendMessage(new RequestAllLocationEdges());
                else if (t == typeof(GameLocation))
                    Communications.SendMessage(new RequestAllGameLocations());
                else if (t == typeof(Reset))
                    Communications.SendMessage(new RequestAllResets());
                else
                    return "Unknown type for data download: " + t.Name;
            }

            return string.Empty;
        }

        public static void StoreThingAsync(this object thing)
        {
            GameLocation loc = thing as GameLocation;
            GameChar gameChar = thing as GameChar;
            Template template = thing as Template;
            GameCharTemplate gameCharTemplate = thing as GameCharTemplate;
            GameThingBaseClass baseClass = thing as GameThingBaseClass;
            Ability ability = thing as Ability;
            State state = thing as State;
            Area area = thing as Area;
            Reset reset = thing as Reset;
            StateTemplate stateTemplate = thing as StateTemplate;
            ItemTemplate itemTemplate = thing as ItemTemplate;
            EdgeData edgeData = thing as EdgeData;
            LocationEdge locEdge = thing as LocationEdge;
            Item item = thing as Item;
            Channel c = thing as Channel;

            if (loc != null)
                Client.StoreGameLocationAsync(DataAccess.AssignedUniqueId, loc);
            else if (locEdge != null)
                Client.StoreLocationEdgeAsync(DataAccess.AssignedUniqueId, locEdge);
            else if (edgeData != null)
                Client.StoreEdgeDataAsync(DataAccess.AssignedUniqueId, edgeData);
            else if (reset != null)
                Client.StoreResetAsync(DataAccess.AssignedUniqueId, reset);
            else if (area != null)
                Client.StoreAreaAsync(DataAccess.AssignedUniqueId, area);
            else if (stateTemplate != null)
                Client.StoreStateTemplateAsync(DataAccess.AssignedUniqueId, stateTemplate);
            else if (itemTemplate != null)
                Client.StoreItemTemplateAsync(DataAccess.AssignedUniqueId, itemTemplate);
            else if (ability != null)
                Client.StoreAbilityAsync(DataAccess.AssignedUniqueId, ability);
            else if (item != null)
                Client.StoreItemAsync(DataAccess.AssignedUniqueId, item);
            else if (gameCharTemplate != null)
                Client.StoreGameCharTemplateAsync(DataAccess.AssignedUniqueId, gameCharTemplate);
            else if (gameChar != null)
                Client.StoreGameCharAsync(DataAccess.AssignedUniqueId, gameChar);
            else if (template != null)
                Client.StoreTemplateAsync(DataAccess.AssignedUniqueId, template);
            else if (c != null)
                Client.StoreChannelAsync(DataAccess.AssignedUniqueId, c);
            else if (baseClass != null)
                Client.StoreGameThingAsync(DataAccess.AssignedUniqueId, baseClass);
            else if (state != null)
                Client.StoreStateAsync(DataAccess.AssignedUniqueId, state);
            else
                throw new Exception("Cannot save object of type " + thing.GetType().Name);
        }

        public static void InitCommunications()
        {
            if (!Initialized)
            {
                Initialized = true;
                Client = new DataServiceClient();
                Client.InnerChannel.OperationTimeout = new TimeSpan(0, 5, 0);
                Client.InnerChannel.Faulted += new EventHandler(InnerChannel_Faulted);
                Client.InnerChannel.AllowOutputBatching = true;

                Client.AssociateIDWithLoginCompleted += new EventHandler<AssociateIDWithLoginCompletedEventArgs>(Client_AssociateIDWithLoginCompleted);
                Client.LoginCompleted += new EventHandler<LoginCompletedEventArgs>(Client_LoginCompleted);
                Client.ReadGameCharactersCompleted += new EventHandler<ReadGameCharactersCompletedEventArgs>(Client_ReadGameCharactersCompleted);
                Client.SetCurrentlyPlayingCompleted += new EventHandler<SetCurrentlyPlayingCompletedEventArgs>(Client_SetCurrentlyPlayingCompleted);
                Client.SendCommandCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(Client_SendCommandCompleted);
                Client.LoadAbilitiesFromIdsCompleted += new EventHandler<LoadAbilitiesFromIdsCompletedEventArgs>(Client_LoadAbilitiesCompleted);
                Client.LoadStatesFromIdsCompleted += new EventHandler<LoadStatesFromIdsCompletedEventArgs>(Client_LoadStatesCompleted);
                Client.ReadAllGameCharactersCompleted += new EventHandler<ReadAllGameCharactersCompletedEventArgs>(Client_ReadAllGameCharactersCompleted);
                Client.ReadAllGameCharacterTemplatesCompleted += new EventHandler<ReadAllGameCharacterTemplatesCompletedEventArgs>(Client_ReadAllGameCharacterTemplatesCompleted);
                Client.ReadWorldMapCompleted += new EventHandler<ReadWorldMapCompletedEventArgs>(Client_ReadWorldMapCompleted);
                Client.StoreAbilityCompleted += new EventHandler<StoreAbilityCompletedEventArgs>(Client_StoreAbilityCompleted);
                Client.StoreGameCharCompleted += new EventHandler<StoreGameCharCompletedEventArgs>(Client_StoreGameCharCompleted);
                Client.StoreGameCharTemplateCompleted += new EventHandler<StoreGameCharTemplateCompletedEventArgs>(Client_StoreGameCharTemplateCompleted);
                Client.StoreStateTemplateCompleted += new EventHandler<StoreStateTemplateCompletedEventArgs>(Client_StoreStateTemplateCompleted);
                Client.StoreGameLocationCompleted += new EventHandler<StoreGameLocationCompletedEventArgs>(Client_StoreGameLocationCompleted);
                Client.StoreGameThingCompleted += new EventHandler<StoreGameThingCompletedEventArgs>(Client_StoreGameThingCompleted);
                Client.StoreStateCompleted += new EventHandler<StoreStateCompletedEventArgs>(Client_StoreStateCompleted);
                Client.StoreMediaCompleted += new EventHandler<StoreMediaCompletedEventArgs>(Client_StoreMediaCompleted);
                Client.StoreTemplateCompleted += new EventHandler<StoreTemplateCompletedEventArgs>(Client_StoreTemplateCompleted);
                Client.ReadLocationEdgesCompleted += new EventHandler<ReadLocationEdgesCompletedEventArgs>(Client_ReadLocationEdgesCompleted);
                Client.ReadByIdCompleted += new EventHandler<ReadByIdCompletedEventArgs>(Client_ReadByIdCompleted);
                Client.ReadStaticMethodsCompleted += new EventHandler<ReadStaticMethodsCompletedEventArgs>(Client_ReadStaticMethodsCompleted);
                Client.StoreChannelCompleted += new EventHandler<StoreChannelCompletedEventArgs>(Client_StoreChannelCompleted);
                Client.LoadChannelsCompleted += new EventHandler<LoadChannelsCompletedEventArgs>(Client_LoadChannelsCompleted);
                Client.ReadAllAreasCompleted += new EventHandler<ReadAllAreasCompletedEventArgs>(Client_ReadAllAreasCompleted);
                Client.ReadAllItemTemplatesCompleted += new EventHandler<ReadAllItemTemplatesCompletedEventArgs>(Client_ReadAllItemTemplatesCompleted);
                Client.StoreItemCompleted += new EventHandler<StoreItemCompletedEventArgs>(Client_StoreItemCompleted);
                Client.StoreItemTemplateCompleted += new EventHandler<StoreItemTemplateCompletedEventArgs>(Client_StoreItemTemplateCompleted);
                Client.StoreAreaCompleted += new EventHandler<StoreAreaCompletedEventArgs>(Client_StoreAreaCompleted);
                Client.StoreResetCompleted += new EventHandler<StoreResetCompletedEventArgs>(Client_StoreResetCompleted);
                Client.StoreLocationEdgeCompleted += new EventHandler<StoreLocationEdgeCompletedEventArgs>(Client_StoreLocationEdgeCompleted);
                Client.StoreEdgeDataCompleted += new EventHandler<StoreEdgeDataCompletedEventArgs>(Client_StoreEdgeDataCompleted);
                Client.CreateCharFromTemplateCompleted += new EventHandler<CreateCharFromTemplateCompletedEventArgs>(Client_CreateCharFromTemplateCompleted);
                Client.CreateItemFromTemplateCompleted += new EventHandler<CreateItemFromTemplateCompletedEventArgs>(Client_CreateItemFromTemplateCompleted);

                RequestAllLocationsComplete += new EventHandler<ObjectEventArgs<ByteDataMessage>>(DataAccess_RequestAllLocationsComplete);
                RequestAllGameCharTemplatesComplete += new EventHandler<ObjectEventArgs<ByteDataMessage>>(DataAccess_RequestAllGameCharTemplatesComplete);
                RequestAllItemTemplatesComplete += new EventHandler<ObjectEventArgs<ByteDataMessage>>(DataAccess_RequestAllItemTemplatesComplete);
                RequestAllItemsComplete += new EventHandler<ObjectEventArgs<ByteDataMessage>>(DataAccess_RequestAllItemsComplete);
                RequestAllAreasComplete += new EventHandler<ObjectEventArgs<ByteDataMessage>>(DataAccess_RequestAllAreasComplete);
                RequestAllLocationEdgesComplete += new EventHandler<ObjectEventArgs<ByteDataMessage>>(DataAccess_RequestAllLocationEdgesComplete);
                RequestAllGameCharsComplete += new EventHandler<ObjectEventArgs<ByteDataMessage>>(DataAccess_RequestAllGameCharsComplete);
                RequestAllResetsComplete += new EventHandler<ObjectEventArgs<ByteDataMessage>>(DataAccess_RequestAllResetsComplete);
                RequestObjectByIdComplete += new EventHandler<ObjectEventArgs<ByteDataMessage>>(DataAccess_RequestObjectByIdComplete);

                Communications.ConnectionError += new EventHandler<ObjectEventArgs<SocketAsyncEventArgs>>(_communications_ConnectionError);
                EnteredGame += new EventHandler(DataAccess_EnteredGame);

                Everything.UnknownThing += new EventHandler<ObjectEventArgsNonRef<long>>(Handle_Unknown_Thing);

                // testing
                Client.ReadStaticMethodsAsync(0);
                Client.LoadChannelsAsync();
            }
        }

        static void Client_CreateItemFromTemplateCompleted(object sender, CreateItemFromTemplateCompletedEventArgs e)
        {
            if (CreateItemCompleted != null)
                CreateItemCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_CreateCharFromTemplateCompleted(object sender, CreateCharFromTemplateCompletedEventArgs e)
        {
            if (CreateCharCompleted != null)
                CreateCharCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        public static void Handle_Unknown_Thing(object sender, ObjectEventArgsNonRef<long> e)
        {
            DownloadSingleObject(e.obj);
        }

        static void DataAccess_RequestObjectByIdComplete(object sender, ObjectEventArgs<ByteDataMessage> e)
        {
            IAssociatedID item = HandleDeserializeSingle(e.obj);
            Everything.Register(item);
        }

        static void Client_StoreMediaCompleted(object sender, StoreMediaCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreMediaCompleted != null)
                StoreMediaCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void DataAccess_RequestAllResetsComplete(object sender, ObjectEventArgs<ByteDataMessage> e)
        {
            List<Reset> items = HandleDeserialize<Reset>(e.obj);
            Record(null, items);

            OnRequestComplete(typeof(Reset), e.obj);
        }

        public static void OnRequestComplete(Type t, ByteDataMessage msg)
        {
            if (RequestComplete != null)
                RequestComplete(null, new ObjectEventArgs<Type, ByteDataMessage>(t, msg));
        }

        static void DataAccess_RequestAllGameCharsComplete(object sender, ObjectEventArgs<ByteDataMessage> e)
        {
            ByteDataMessage msg = e.obj;
            byte[] b = msg.Bytes;
            byte[] decompressed = b.Decompress();
            Serializer s = new Serializer();
            foreach (var type in IncomingMessageHandler.KnownTypesArray)
                s.CacheObject(type);
            List<GameChar> gameChars = (List<GameChar>)s.Deserialize(decompressed, typeof(List<GameChar>));
            RecordGameChars(null, gameChars);

            OnRequestComplete(typeof(GameChar), e.obj);
        }

        static void DataAccess_RequestAllLocationEdgesComplete(object sender, ObjectEventArgs<ByteDataMessage> e)
        {
            List<LocationEdge> items = HandleDeserialize<LocationEdge>(e.obj);
            Record(null, items);
            LinkUpLocationEdges();

            OnRequestComplete(typeof(LocationEdge), e.obj);
        }

        static void DataAccess_RequestAllAreasComplete(object sender, ObjectEventArgs<ByteDataMessage> e)
        {
            List<Area> items = HandleDeserialize<Area>(e.obj);
            Record(null, items);

            OnRequestComplete(typeof(Area), e.obj);
        }

        static void DataAccess_RequestAllItemsComplete(object sender, ObjectEventArgs<ByteDataMessage> e)
        {
            List<Item> items = HandleDeserialize<Item>(e.obj);
            Record(null, items);

            OnRequestComplete(typeof(Item), e.obj);
        }

        static void DataAccess_RequestAllItemTemplatesComplete(object sender, ObjectEventArgs<ByteDataMessage> e)
        {
            List<ItemTemplate> templates = HandleDeserialize<ItemTemplate>(e.obj);
            Record(null, templates);

            OnRequestComplete(typeof(ItemTemplate), e.obj);
        }

        static void DataAccess_RequestAllGameCharTemplatesComplete(object sender, ObjectEventArgs<ByteDataMessage> e)
        {
            List<GameCharTemplate> templates = HandleDeserialize<GameCharTemplate>(e.obj);
            Record(null, templates);

            OnRequestComplete(typeof(GameCharTemplate), e.obj);
        }

        static void DataAccess_RequestAllLocationsComplete(object sender, ObjectEventArgs<ByteDataMessage> e)
        {
            List<GameLocation> locations = HandleDeserialize<GameLocation>(e.obj);
            RecordWorldMap(null, locations);

            OnRequestComplete(typeof(GameLocation), e.obj);
        }

        static void Client_StoreEdgeDataCompleted(object sender, StoreEdgeDataCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreEdgeDataCompleted != null)
                StoreEdgeDataCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_StoreLocationEdgeCompleted(object sender, StoreLocationEdgeCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreLocationEdgeCompleted != null)
                StoreLocationEdgeCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_StoreResetCompleted(object sender, StoreResetCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreResetCompleted != null)
                StoreResetCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_StoreAreaCompleted(object sender, StoreAreaCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreAreaCompleted != null)
                StoreAreaCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_StoreItemTemplateCompleted(object sender, StoreItemTemplateCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreItemTemplateCompleted != null)
                StoreItemTemplateCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_StoreItemCompleted(object sender, StoreItemCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreItemCompleted != null)
                StoreItemCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_ReadAllItemTemplatesCompleted(object sender, ReadAllItemTemplatesCompletedEventArgs e)
        {
            foreach (var v in e.Result)
                Everything.Register(v);
        }

        static void Client_ReadAllAreasCompleted(object sender, ReadAllAreasCompletedEventArgs e)
        {
            foreach (var v in e.Result)
                Everything.Register(v);
        }

        static void Client_LoadChannelsCompleted(object sender, LoadChannelsCompletedEventArgs e)
        {
            Channels = e.Result;
        }

        static void Client_StoreChannelCompleted(object sender, StoreChannelCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreChannelCompleted != null)
                StoreChannelCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_ReadStaticMethodsCompleted(object sender, ReadStaticMethodsCompletedEventArgs e)
        {
            _methods = e.Result.ToList();
        }

        static void Client_ReadByIdCompleted(object sender, ReadByIdCompletedEventArgs e)
        {
            object result = null;
            Type t = TypeProvider.GetInstance().GetType(e.Result.Type);
            DataContractSerializer s = new DataContractSerializer(t);
            using (MemoryStream ms = new MemoryStream(UTF8Encoding.UTF8.GetBytes(e.Result.Bytes)))
            {
                result = s.ReadObject(ms);
            }
            (result as IAssociatedID).Register();
        }

        static void Client_StoreGameLocationCompleted(object sender, StoreGameLocationCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreGameLocationCompleted != null)
                StoreGameLocationCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_StoreStateTemplateCompleted(object sender, StoreStateTemplateCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreStateTemplateCompleted != null)
                StoreStateTemplateCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void InnerChannel_Faulted(object sender, EventArgs e)
        {
            Debug.WriteLine("UGH");
            Console.WriteLine("UGH");
        }

        static void Client_ReadLocationEdgesCompleted(object sender, ReadLocationEdgesCompletedEventArgs e)
        {
            foreach (var edge in e.Result)
            {
                Everything.Register(edge);
            }

            //Client.ReadWorldMapAsync();            
        }

        static void Client_StoreTemplateCompleted(object sender, StoreTemplateCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreTemplateCompleted != null)
                StoreTemplateCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_StoreStateCompleted(object sender, StoreStateCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreStateCompleted != null)
                StoreStateCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_StoreGameThingCompleted(object sender, StoreGameThingCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreGameThingCompleted != null)
                StoreGameThingCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_StoreGameCharTemplateCompleted(object sender, StoreGameCharTemplateCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreGameCharTemplateCompleted != null)
                StoreGameCharTemplateCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_StoreGameCharCompleted(object sender, StoreGameCharCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreGameCharCompleted != null)
                StoreGameCharCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        static void Client_StoreAbilityCompleted(object sender, StoreAbilityCompletedEventArgs e)
        {
            LastStoredId = e.Result;

            if (StoreAbilityCompleted != null)
                StoreAbilityCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));

            if (StoreCompleted != null)
                StoreCompleted(sender, new ObjectEventArgsNonRef<long>(e.Result));
        }

        public static void RecordWorldMap(object sender, List<GameLocation> results)
        {
            for (int n = 0; n < results.Count; n++)
            {
                GameLocation loc = results[n];
                LocalWorld[loc.XYZ.X, loc.XYZ.Y, loc.XYZ.Z] = loc;
                Everything.Register(loc);
            }

            for (int n = 0; n < results.Count; n++)
            {
                GameLocation loc = results[n];
                loc.RecalculateEdges();
            }

            WorldMap.Instance.World = LocalWorld;

            if (LocalWorldRead != null)
                LocalWorldRead(sender, new EventArgs());
        }

        static void Client_ReadWorldMapCompleted(object sender, ReadWorldMapCompletedEventArgs e)
        {
            RecordWorldMap(sender, e.Result.ToList());
        }

        static void Client_ReadAllGameCharacterTemplatesCompleted(object sender, ReadAllGameCharacterTemplatesCompletedEventArgs e)
        {
            List<GameCharTemplate> list = new List<GameCharTemplate>();

            for (int n = 0; n < e.Result.Count; n++)
            {
                list.Add(e.Result[n]);
            }

            Record<GameCharTemplate>(sender, list);
        }

        public static void LinkUpLocationEdges()
        {
            List<GameLocation> locs = Everything.FindAllThingsOfType<GameLocation>();

            foreach (var loc in locs)
            {
                loc.RecalculateEdges();
            }
        }

        public static void Record<T>(object sender, List<T> list) where T : class, IGameThing
        {
            list.AddToEverything();

            if (typeof(GameLocation).IsAssignableFrom(typeof(T)))
            {
                foreach (var locObj in list)
                {
                    GameLocation loc = locObj as GameLocation;

                    if (loc.HasResets)
                    {
                        foreach (var resetID in loc.Resets.AllIDs)
                        {
                            var reset = Everything.Find<Reset>(resetID);

                            if (reset != null)
                            {
                                Everything.Register(reset);
                            }
                        }
                    }
                }
            }
        }

        public static void RecordGameChars(object sender, List<GameChar> list)
        {
            list.AddToEverything();

            if (GameCharactersRead != null)
                GameCharactersRead(sender, new EventArgs());
        }

        static void Client_ReadAllGameCharactersCompleted(object sender, ReadAllGameCharactersCompletedEventArgs e)
        {
            List<GameChar> list = new List<GameChar>();
            for (int n = 0; n < e.Result.Count; n++)
            {
                list.Add(e.Result[n]);
            }
            RecordGameChars(sender, list);

            // HEREHERE DataAccess.Client.ReadAllGameCharacterTemplatesAsync(DataAccess.AssignedUniqueId, DataAccess.CurrentLogin);
            // HEREHERE DataAccess.Client.ReadAllItemTemplatesAsync(DataAccess.AssignedUniqueId, DataAccess.CurrentLogin);
            // HEREHERE DataAccess.Client.ReadAllAreasAsync(DataAccess.AssignedUniqueId, DataAccess.CurrentLogin);
        }

        public static ThreadSafeLookupNonRef<long, long> ReadAbilities = new ThreadSafeLookupNonRef<long, long>();
        public static ThreadSafeLookupNonRef<long, long> ReadStates = new ThreadSafeLookupNonRef<long, long>();

        public static void CheckLoadStates()
        {
            //Client.ReadLocationEdgesAsync();

            var ids2 = new ObservableCollection<long>();
            foreach (var l in ReadStates.AllItems) ids2.Add(l);
            ReadStates.Clear();
            Client.LoadStatesFromIdsAsync(ids2);
        }

        public static void CheckLoadAbilities()
        {
            var ids = new ObservableCollection<long>();
            foreach (var l in ReadAbilities.AllItems) ids.Add(l);
            ReadAbilities.Clear();
            Client.LoadAbilitiesFromIdsAsync(ids);
        }

        public static void Client_LoadStatesCompleted(object sender, LoadStatesFromIdsCompletedEventArgs e)
        {
            e.Result.ToList().AddToEverything();
        }

        public static void Client_LoadAbilitiesCompleted(object sender, LoadAbilitiesFromIdsCompletedEventArgs e)
        {
            e.Result.ToList().AddToEverything();
        }

        static void Client_SendCommandCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            // HEREHERE
            Debug.WriteLine("Sent");
            Console.WriteLine("Sent");
        }

        static void Client_SetCurrentlyPlayingCompleted(object sender, SetCurrentlyPlayingCompletedEventArgs e)
        {
            // HEREHERE
            CurrentlyPlaying = e.Result;

            if (CurrentlyPlayingChanged != null)
                CurrentlyPlayingChanged(sender, new EventArgs());
        }

        public static void RaiseEnteredGame(object sender, GameChar gameChar)
        {
            CurrentlyPlayingId = gameChar.AssociatedID;

            if (EnteredGame != null)
                EnteredGame(sender, new EventArgs());
        }

        static void DataAccess_EnteredGame(object sender, EventArgs e)
        {
            Client.SetCurrentlyPlayingAsync(AssignedUniqueId, CurrentLogin, CurrentlyPlayingId);
            OnWantEnableHUD();
        }

        public static void OnWantEnableHUD()
        {
            if (WantEnableHUD != null)
                WantEnableHUD(null, new EventArgs());
        }

        public static void AddToEverything<T>(this List<T> items) where T : class, IAssociatedID
        {
            foreach (var item in items)
            {
                Everything.Register(item);
            }
        }

        static void Client_ReadGameCharactersCompleted(object sender, ReadGameCharactersCompletedEventArgs e)
        {
            if (e.Result != null)
            {
                UsersGameCharacters = e.Result.ToList();
                UsersGameCharacters.AddToEverything();

                foreach (var chr in UsersGameCharacters)
                {
                    foreach (var l in chr.Abilities.AllIDs) ReadAbilities.AddOrSet(l, l);
                    foreach (var l in chr.States.AllIDs) ReadStates.AddOrSet(l, l);
                }

                CheckLoadStates();
                CheckLoadAbilities();

                if (UsersGameCharactersRead != null)
                    UsersGameCharactersRead(sender, e);
            }
        }

        static void Client_LoginCompleted(object sender, LoginCompletedEventArgs e)
        {
            if (e.Result != null)
            {
                CurrentLogin = e.Result;

                if (LoginSuccessful != null)
                    LoginSuccessful(sender, e);

                //Communications.SendMessage(new RequestAllGameLocations());
                //Communications.SendMessage(new RequestAllGameCharTemplates());
                Communications.SendMessage(new RequestAllGameChars());
                return;
            }

            if (LoginUnsuccessful != null)
                LoginUnsuccessful(sender, e);
        }

        static void Client_AssociateIDWithLoginCompleted(object sender, AssociateIDWithLoginCompletedEventArgs e)
        {
        }

        public static SilverlightCommClient Communications
        {
            get
            {
                if (_communications == null)
                {
                    if (Interlocked.CompareExchange<SilverlightCommClient>(ref _communications, new SilverlightCommClient(), null) == null)
                    {
                        _communications.ConnectionEstablished += new EventHandler<ObjectEventArgs<UserConnection>>(_communications_ConnectionEstablished);
                        _communications.SocketErrorOccurred += new EventHandler<ObjectEventArgs<SocketAsyncEventArgs>>(_communications_SocketErrorOccurred);
                        _communications.ReceivedData += new EventHandler<ObjectEventArgs<byte[]>>(_communications_ReceivedData);
                        _communications.ConnectToServer(RemoteHostName);
                    }
                }
                return _communications;
            }
        }

        public static void HandleStringMessage(StringMessage msg)
        {
            if (msg.String1 == "LocationInt")
            {
                LocationInt loc = msg.String2.ParseLocationInt();
                long location = Convert.ToInt64(msg.String3);
                OnThingMoved(msg.ID, loc, location);
            }
        }

        public static void OnThingMoved(long id, LocationInt loc, long location)
        {
            if (CurrentlyPlaying != null && CurrentlyPlaying.LocationInt != loc)
            {
                CurrentlyPlaying.LocationInt = loc;
                CurrentlyPlaying.Location = location;
            }

            if (ThingMoved != null)
            {
                ThingMoved(null, new ObjectEventArgsNonRef<long, LocationInt, long>(id, loc, location));
            }
        }

        public static void _communications_ReceivedData(object sender, ObjectEventArgs<byte[]> e)
        {
            lock (_lock)
            {
                Message m = null;
                byte[] bytes = e.obj;

                //e.obj.IncomingBytes.Seek(0, SeekOrigin.Begin);
                //byte[] lenBytes = new byte[4];
                //e.obj.IncomingBytes.Read(lenBytes, 0, 4);
                //using (MemoryStream ms = new MemoryStream(lenBytes))
                //{
                //    using (BinaryReader br = new BinaryReader(ms))
                //    {
                //        int len = br.ReadInt32();
                //        if (e.obj.IncomingBytes.Length < len + 8)
                //        {
                //            e.obj.IncomingBytes.Seek(0, SeekOrigin.End);
                //            return;
                //        }
                //    }
                //}
                //bytes = e.obj.IncomingBytes.ToArray();
                //e.obj.IncomingBytes.SetLength(0);

                using (MemoryStream ms = new MemoryStream(bytes))
                {
                    using (BinaryReader br = new BinaryReader(ms))
                    {
                        int len = br.ReadInt32();
                        int type = br.ReadInt32();
                        byte[] theBytes = br.ReadBytes(len);
                        if (theBytes.Length != len)
                        {
                            // HEREHERE
                            Debug.WriteLine("BLAH");
                            Console.Write("BLAH");
                        }
                        m = new Message(theBytes, type, new MessageHeader(len, type));
                    }
                }

                if (m != null)
                {
                    try
                    {
                        switch ((TransmissionEnum)m.MessageType)
                        {
                            case TransmissionEnum.RespondUniqueId:
                                {
                                    NumericMessage msg = m.MessageContents as NumericMessage;
                                    AssignedUniqueId = msg.Numeric;
                                    break;
                                }

                            case TransmissionEnum.NotificationMessageText:
                                {
                                    NotificationMessageText msg = m.MessageContents as NotificationMessageText;
                                    OnNotificationTextReceived(sender, msg.Text);
                                    break;
                                }

                            case TransmissionEnum.NotificationMessageTextWithSource:
                                {
                                    NotificationMessageTextWithSource msg = m.MessageContents as NotificationMessageTextWithSource;
                                    OnNotificationTextReceived(sender, msg.Source + ": " + msg.Text);
                                    break;
                                }

                            case TransmissionEnum.StringAndNumeric:
                                {
                                    StringAndNumeric msg = m.MessageContents as StringAndNumeric;
                                    OnUpdatePropertyValue(sender, msg.Text, msg.Numeric);
                                    break;
                                }

                            case TransmissionEnum.StringMessage:
                                {
                                    StringMessage msg = m.MessageContents as StringMessage;
                                    HandleStringMessage(msg);
                                    break;
                                }

                            case TransmissionEnum.RequestAllLocations:
                                {
                                    if (RequestAllLocationsComplete != null)
                                        RequestAllLocationsComplete(null, new ObjectEventArgs<ByteDataMessage>(m.MessageContents as ByteDataMessage));

                                    //Communications.SendMessage(new RequestAllGameCharTemplates());
                                    Communications.SendMessage(new RequestAllAreas());
                                    break;
                                }

                            case TransmissionEnum.RequestAllGameCharTemplates:
                                {
                                    if (RequestAllGameCharTemplatesComplete != null)
                                        RequestAllGameCharTemplatesComplete(null, new ObjectEventArgs<ByteDataMessage>(m.MessageContents as ByteDataMessage));

                                    //Communications.SendMessage(new RequestAllItemTemplates());
                                    break;
                                }

                            case TransmissionEnum.RequestAllItemTemplates:
                                {
                                    if (RequestAllItemTemplatesComplete != null)
                                        RequestAllItemTemplatesComplete(null, new ObjectEventArgs<ByteDataMessage>(m.MessageContents as ByteDataMessage));

                                    //Communications.SendMessage(new RequestAllItems());
                                    break;
                                }

                            case TransmissionEnum.RequestAllItems:
                                {
                                    if (RequestAllItemsComplete != null)
                                        RequestAllItemsComplete(null, new ObjectEventArgs<ByteDataMessage>(m.MessageContents as ByteDataMessage));

                                    //Communications.SendMessage(new RequestAllAreas());
                                    break;
                                }

                            case TransmissionEnum.RequestAllAreas:
                                {
                                    if (RequestAllAreasComplete != null)
                                        RequestAllAreasComplete(null, new ObjectEventArgs<ByteDataMessage>(m.MessageContents as ByteDataMessage));

                                    Communications.SendMessage(new RequestAllLocationEdges());
                                    break;
                                }

                            case TransmissionEnum.RequestAllLocationEdges:
                                {
                                    if (RequestAllLocationEdgesComplete != null)
                                        RequestAllLocationEdgesComplete(null, new ObjectEventArgs<ByteDataMessage>(m.MessageContents as ByteDataMessage));

                                    // HEREHERE
                                    break;
                                }

                            case TransmissionEnum.RequestAllGameChars:
                                {
                                    if (RequestAllGameCharsComplete != null)
                                        RequestAllGameCharsComplete(null, new ObjectEventArgs<ByteDataMessage>(m.MessageContents as ByteDataMessage));

                                    // Communications.SendMessage(new RequestAllResets());
                                    Communications.SendMessage(new RequestAllGameLocations());
                                    break;
                                }

                            case TransmissionEnum.RequestAllResets:
                                {
                                    if (RequestAllResetsComplete != null)
                                        RequestAllResetsComplete(null, new ObjectEventArgs<ByteDataMessage>(m.MessageContents as ByteDataMessage));

                                    // Communications.SendMessage(new RequestAllGameLocations());
                                    break;
                                }
                            case TransmissionEnum.RequestObjectById:
                                {
                                    if (RequestObjectByIdComplete != null)
                                        RequestObjectByIdComplete(null, new ObjectEventArgs<ByteDataMessage>(m.MessageContents as ByteDataMessage));

                                    break;
                                }
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex.ToString());
                        Console.WriteLine(ex.ToString());
                    }
                }
            }
        }

        public static List<T> HandleDeserialize<T>(ByteDataMessage msg) where T : IGameThing
        {
            byte[] b = msg.Bytes;
            byte[] decompressed = b.Decompress();
            Serializer s = new Serializer();
            foreach (var type in IncomingMessageHandler.KnownTypesArray)
                s.CacheObject(type);
            List<T> items = (List<T>)s.Deserialize(decompressed, typeof(List<T>));
            return items;
        }

        public static IAssociatedID HandleDeserializeSingle(ByteDataMessage msg)
        {
            byte[] b = msg.Bytes;
            byte[] decompressed = b.Decompress();
            Serializer s = new Serializer();
            foreach (var type in IncomingMessageHandler.KnownTypesArray)
                s.CacheObject(type);
            IAssociatedID item = (IAssociatedID)s.Deserialize(decompressed);
            return item;
        }

        public static void OnUpdatePropertyValue(object sender, string text, int numeric)
        {
            if (UpdatePropertyValue != null)
                UpdatePropertyValue(sender, new ObjectEventArgs<string, object>(text, numeric));
        }

        public static void OnNotificationTextReceived(object sender, string text)
        {
            if (NotificationTextReceived != null)
                NotificationTextReceived(sender, new ObjectEventArgs<string>(text));
        }

        static void _communications_SocketErrorOccurred(object sender, ObjectEventArgs<System.Net.Sockets.SocketAsyncEventArgs> e)
        {
            if (SocketErrorOccurred != null)
                SocketErrorOccurred(sender, e);
        }

        static void _communications_ConnectionEstablished(object sender, ObjectEventArgs<UserConnection> e)
        {
            Communications.SendMessage(new NumericMessage() { Numeric = 0 });
        }

        static void _communications_ConnectionError(object sender, ObjectEventArgs<SocketAsyncEventArgs> e)
        {
            if (ConnectionErrorOccurred != null)
                ConnectionErrorOccurred(sender, e);
        }

        public static void SendTestMessage()
        {
            InitCommunications();
        }

        public static void Login(string login, string password)
        {
            InitCommunications();
            Client.LoginAsync(AssignedUniqueId, new UsernamePassword() { UserName = login, Password = password });
        }
    }
}

//DataContractSerializer ser = new DataContractSerializer(typeof(List<GameLocation>));
//using (MemoryStream ms = new MemoryStream(decompressed))
//{
//    RecordWorldMap(null, (List<GameLocation>)ser.ReadObject(ms));
//}
